/*******************************************************************************
 * Copyright 2012 Francesco Foresti
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *******************************************************************************/
package it.fflabs.dynscript.client;

import com.google.gwt.core.client.JavaScriptObject;

import it.fflabs.dynscript.client.handler.JsHandler;

/**
 * <b>gwt-jsClient : JsClient</b><br>
 * <hr>
 * Comment: This is the class that creates the dynamic script tag and puts it
 * into the DOM. It also receives the JSON data in response to the GET call done
 * by the script tag.<br/>
 * 
 * For more informations on this and other related techniques, see
 * <ul>
 * <li><a
 * href="http://www.xml.com/pub/a/2005/12/21/json-dynamic-script-tag.html">
 * http://www.xml.com/pub/a/2005/12/21/json-dynamic-script-tag.html</a></li>
 * <li><a href="http://goessner.net/2006/01/remote-json.html">
 * http://goessner.net/2006/01/remote-json.html</a></li>
 * <li><a
 * href="http://code.google.com/webtoolkit/doc/latest/tutorial/Xsite.html">
 * http://code.google.com/webtoolkit/doc/latest/tutorial/Xsite.html</a></li>
 * <li><a href=
 * "http://code.google.com/webtoolkit/articles/using_gwt_for_json_mashups.html">
 * http
 * ://code.google.com/webtoolkit/articles/using_gwt_for_json_mashups.html</a></li>
 * </ul>
 * <br>
 * <hr>
 * 12/dic/2011<br>
 * 
 * @author Francesco Foresti
 * 
 */
public class JsClient {

	// TODO : create doPost
	//
	// How do we make a POST call?
	//
	// http://stackoverflow.com/questions/3601804/gwt-how-to-send-post-cross-domain-requests-with-json
	// http://hacks.mozilla.org/2009/07/cross-site-xmlhttprequest-with-cors/
	// http://arunranga.com/examples/access-control/
	//
	// FORM
	// http://javascript.about.com/library/blforms.htm
	// http://www.coderanch.com/t/120264/GWT/GWT-HTTP-post-requests
	// http://wiki.magnolia-cms.com/display/WIKI/How+to+use+GWT+to+build,+validate+and+submit+a+form

	private static final int DEFAULT_TIMEOUT = 5000;
	private static volatile int id = 0;

	/**
	 * invokes the service at the specified url.
	 * 
	 * 
	 * @param url
	 * @param handler
	 * @param timeout
	 *            milliseconds before the client returns null. This value must
	 *            be > 250, otherwise default value (5000) is used. <b>NOTE</b>
	 *            since the client (browser) will be unresponsive until timeout
	 *            expires or the service response is received completely ,
	 *            choose this value <b>with extreme care</b>
	 */
	public static void doGet(String url, JsHandler handler, int timeout) {
		if (!url.startsWith("http://") && !url.startsWith("https://")) {
			url = "http://" + url;
		}
		if (url.endsWith("/")) {
			url = url.substring(0, url.lastIndexOf("/"));
		}
		// check if there already is the "callback" parameter,
		// then check if there is some other parameter in the url,
		if (!url.contains("callback=")) {
			if (url.contains("?") && url.contains("=")) {
				url += "&";
			} else {
				url += "?";
			}
			url += "callback=";
		}
		if (timeout <= 250) {
			timeout = DEFAULT_TIMEOUT;
		}
		JsClient.doGet(id++, url, handler, timeout);
	}

	/**
	 * Make the call to the remote server.
	 */
	private native static void doGet(int requestId, String url,
			JsHandler handler, int timeout) /*-{
											var callback = "callback" + requestId;

											var script = document.createElement("script");
											script.setAttribute("src", url + callback);
											script.setAttribute("type", "text/javascript");

											var responseCallback = function(jsonObj) {
											var objType = typeof jsonObj;
											var response;
											if(objType != 'object') {
											response = @it.fflabs.dynscript.client.JsClient::parseJson(Ljava/lang/String;)(jsonObj)
											} else {
											response = jsonObj;
											}
											handler.@it.fflabs.dynscript.client.handler.JsHandler::handleResponse(Lcom/google/gwt/core/client/JavaScriptObject;)(response);			
											window[callback + "done"] = true;
											}
											window[callback] = responseCallback;

											var timeoutCallback = function() {
											if (!window[callback + "done"]) {
											handler.@it.fflabs.dynscript.client.handler.JsHandler::handleTimeout()();
											}
											document.body.removeChild(script);
											delete window[callback];
											delete window[callback + "done"];
											}
											setTimeout(timeoutCallback, timeout);
											document.body.appendChild(script);
											
											}-*/;

	/*
	 * See
	 * http://code.google.com/webtoolkit/doc/latest/DevGuideCodingBasicsJSON.
	 * html#parsing Takes in a trusted JSON String and evals it.
	 * 
	 * @param JSON String that you trust
	 * 
	 * @return JavaScriptObject that you can cast to an Overlay Type
	 */
	private static native JavaScriptObject parseJson(String jsonStr) /*-{
																		return JSON.parse(jsonStr);
																		}-*/;
}
